package org.example.datasource.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONPath;
import org.example.JdbcUrlParser;
import org.example.SqlTablePrefixer;
import org.example.datasource.DataSourceApi;
import org.example.datasource.impl.resp.OpenApiFieldMetadataVo;
import org.example.datasource.impl.resp.OpenApiTableMetadataVo;
import org.example.datasource.model.FieldMetadata;
import org.example.datasource.model.JdbcDataSourceInfo;
import org.example.datasource.model.TableMetadata;
import org.example.model.JdbcInfo;

import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DataLinkMedataDataSourceImpl implements DataSourceApi {
    JdbcDataSourceInfo jdbcDataSourceInfo;
    JdbcInfo jdbcInfo;

    public static String address = "";

    public DataLinkMedataDataSourceImpl(JdbcDataSourceInfo jdbcDataSourceInfo) {
        this.jdbcDataSourceInfo = jdbcDataSourceInfo;
        jdbcInfo =  JdbcUrlParser.parseJdbcUrl(jdbcDataSourceInfo.getUrl());
        if (jdbcInfo == null){
            System.out.println(jdbcDataSourceInfo.getUrl());
            System.out.println("JDBC 未实现");
        }

    }


    @Override
    public List<TableMetadata> getTableMetadata(List<String> tables) {
        List<String> tableNames = null;

        Map<String, Object> params = new HashMap<>();


        params.put("ip", jdbcInfo.getIp());
        params.put("port", jdbcInfo.getPort());

        params.put("tableNames", tableNames);

        params.put("databaseName", jdbcInfo.getDatabase());

        params.put("pageSize", 100);
        String response =  HttpUtil.createGet(address + "/api/openApi/table/metadata")
                .form(params).execute().body();
        Object ret = path.extract(response);
//        if (ret == null){
//            System.out.println(address + "/api/openApi/table/metadata");
//        }
        List<OpenApiTableMetadataVo> openApiTableMetadataVos = JSON.parseArray(ret.toString(),OpenApiTableMetadataVo.class);
        List<TableMetadata> tableMetadatas = new ArrayList<>();
        for (OpenApiTableMetadataVo openApiTableMetadataVo : openApiTableMetadataVos) {
            TableMetadata tableMetadata1 = new TableMetadata();

            tableMetadata1.setTableName(openApiTableMetadataVo.getTableName());

            tableMetadata1.setIp(openApiTableMetadataVo.getDatasource().getIp());

            tableMetadata1.setPort(openApiTableMetadataVo.getDatasource().getPort().toString());


            tableMetadata1.setDatabaseName(openApiTableMetadataVo.getDatasource().getDatabaseName());

            List<FieldMetadata> fields = new ArrayList<>();
            for (OpenApiFieldMetadataVo fieldMetadata : openApiTableMetadataVo.getFieldMetadatas()) {
                FieldMetadata fieldMetadata1 = new FieldMetadata();
                fieldMetadata1.setType(fieldMetadata.getType());
                fieldMetadata1.setFileName(fieldMetadata.getFieldName());
                fields.add(fieldMetadata1);
            }

            tableMetadata1.setFields(fields);

            tableMetadatas.add(tableMetadata1);
        }
        return tableMetadatas;
    }
    JSONPath path = JSONPath.of("$.data.data");

    @Override
    public List<TableMetadata> getTableMetadata(String sql,boolean isSink) {
        List<String> tableNames = null;
        if (isSink){
            tableNames = List.of(getSinkTableName(sql));
        }else {
            tableNames = getAllTableName(sql);
        }
        Map<String, Object> params = new HashMap<>();


        params.put("ip", jdbcInfo.getIp());
        params.put("port", jdbcInfo.getPort());

        params.put("tableNames", tableNames);

        if (jdbcInfo.getType().equals("oracle")){
            params.put("databaseName",SqlTablePrefixer.getAllSchemaNames(sql));
        }else {
            params.put("databaseName", jdbcInfo.getDatabase());
        }
        params.put("pageSize", 100);
        String response =  HttpUtil.createPost(address + "/api/openApi/table/metadata")
                .form(params).execute().body();
        Object ret = path.extract(response);
        if(ret == null){
            System.out.println(response);
        }
        List<OpenApiTableMetadataVo> openApiTableMetadataVos = JSON.parseArray(ret.toString(),OpenApiTableMetadataVo.class);
        List<TableMetadata> tableMetadatas = new ArrayList<>();
        for (OpenApiTableMetadataVo openApiTableMetadataVo : openApiTableMetadataVos) {
            TableMetadata tableMetadata1 = new TableMetadata();

            tableMetadata1.setTableName(openApiTableMetadataVo.getTableName());

            tableMetadata1.setIp(openApiTableMetadataVo.getDatasource().getIp());

            tableMetadata1.setPort(openApiTableMetadataVo.getDatasource().getPort().toString());


            tableMetadata1.setDatabaseName(openApiTableMetadataVo.getDatasource().getDatabaseName());

            List<FieldMetadata> fields = new ArrayList<>();
            for (OpenApiFieldMetadataVo fieldMetadata : openApiTableMetadataVo.getFieldMetadatas()) {
                FieldMetadata fieldMetadata1 = new FieldMetadata();
                fieldMetadata1.setType(fieldMetadata.getType());
                fieldMetadata1.setFileName(fieldMetadata.getFieldName());
                fields.add(fieldMetadata1);
            }

            tableMetadata1.setFields(fields);

            tableMetadatas.add(tableMetadata1);
        }
        return tableMetadatas;
    }



    private List<String> getAllTableName(String sql){

       return SqlTablePrefixer.getAllTableNames(sql);
    }

    public static String getSinkTableName(String sql) {
        System.out.println(sql);
        // 查找 INSERT INTO 之后的部分
        int startIndex = sql.toUpperCase().indexOf("INSERT INTO") + "INSERT INTO".length();
        int endIndex = sql.indexOf("(", startIndex);

        if (startIndex != -1 && endIndex != -1) {
            // 提取表名
            String tableName = sql.substring(startIndex, endIndex).trim();
            // 替换原表名为带前缀的表名
            // 构造新的SQL语句
            return tableName;
        }
        return null;
    }
}
